

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon%2032x32.ico">
  <link rel="icon" href="/img/favicon%2032x32.ico">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="hypocrite30">
  <meta name="keywords" content="">
  
  <title>Java常见细节 - hypocrite30</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10.4.0/styles/idea.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
  



<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"hypocrite30.gitee.io","root":"/","version":"1.8.9","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":"§"},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":2},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":"b5f391eebc7eaea88e68a49d5924e381","google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null}}};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.3.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>Hypocrite30 BLOG</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/postPage.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Java常见细节">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-05-15 20:55" pubdate>
        2021年5月15日 晚上
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      2.5k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      47
       分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Java常见细节</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：2021年5月15日 晚上
                
              </p>
            
            <div class="markdown-body">
              <h1 id="Java常见细节"><a href="#Java常见细节" class="headerlink" title="Java常见细节"></a>Java常见细节</h1><h2 id="1-「replace会替换所有字符？」"><a href="#1-「replace会替换所有字符？」" class="headerlink" title="1. 「replace会替换所有字符？」"></a>1. 「replace会替换所有字符？」</h2><p>如果将字符串中 <code>A</code> 替换为 <code>B</code> ，则使用 <code>replaceAll</code> 方法。</p>
<p><code>replace</code> 会替换所有匹配字符吗？</p>
<blockquote>
<p>Replaces each substring of this string that matches the literal target sequence with the specified literal replacement sequence. The replacement proceeds from the beginning of the string to the end, for example, replacing “aa” with “b” in the string “aaa” will result in “ba” rather than “ab”.</p>
</blockquote>
<ul>
<li>替换从字符串的开头一直进行到结尾，匹配成功就替换，然后接下去。</li>
<li>例如：原字符串：<code>aaa</code> ，将 <code>aa</code> 替换为 <code>b</code> ，则结果是 <code>ba</code> 而不是 <code>ab</code> ，因为是从前往后。</li>
</ul>
<ol>
<li><code>replace</code>  两个重载方法</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">replace</span><span class="hljs-params">(<span class="hljs-keyword">char</span> oldChar, <span class="hljs-keyword">char</span> newChar)</span> <span class="hljs-comment">/* 替换一个字符 */</span></span><br></code></pre></div></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">replace</span><span class="hljs-params">(CharSequence target, CharSequence replacement)</span> <span class="hljs-comment">/* 替换一个串 */</span></span><br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li><code>replaceAll</code> </li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">replaceAll</span><span class="hljs-params">(String regex, String replacement)</span> <span class="hljs-comment">/* 前面正则表达式，匹配成功替换为后面字符串 */</span></span><br></code></pre></div></td></tr></table></figure>
<p>举例🌰：原串 s 里的 <code>*</code> 替换为 <code>A</code> 两种写法：</p>
<ul>
<li><code>s.replaceAll(&quot;\\*&quot;, &quot;A&quot;)</code> 只能接正则表达式匹配出来替换。</li>
<li><code>s.replace(&quot;*&quot;, &quot;A&quot;)</code> </li>
</ul>
<ol start="3">
<li><code>replaceFirst</code> 只替换第一个匹配字符串</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">replaceFirst</span><span class="hljs-params">(String regex, String replacement)</span></span><br></code></pre></div></td></tr></table></figure>


<h2 id="2-「Integer不能用-判断？」"><a href="#2-「Integer不能用-判断？」" class="headerlink" title="2. 「Integer不能用 == 判断？」"></a>2. 「Integer不能用 == 判断？」</h2><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Integer orderStatus1 = <span class="hljs-keyword">new</span> Integer(<span class="hljs-number">1</span>);<br>Integer orderStatus2 = <span class="hljs-keyword">new</span> Integer(<span class="hljs-number">1</span>);<br>System.out.println(orderStatus1 == orderStatus2);<br></code></pre></div></td></tr></table></figure>
<ul>
<li>结果会返回 <code>false</code> </li>
<li>不是说 Integer 有缓存吗，范围是 -128 ~ 127</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Integer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>&#123;<br>    <span class="hljs-keyword">this</span>.value = value;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>有参构造并<strong>没有</strong>用到缓存</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Integer <span class="hljs-title">valueOf</span><span class="hljs-params">(<span class="hljs-keyword">int</span> i)</span> </span>&#123;<br>    <span class="hljs-keyword">if</span> (i &gt;= IntegerCache.low &amp;&amp; i &lt;= IntegerCache.high)<br>        <span class="hljs-keyword">return</span> IntegerCache.cache[i + (-IntegerCache.low)];<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Integer(i);<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>要用到缓存，就应该使用 <code>valueOf</code> 方法</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">String orderStatus1 = <span class="hljs-keyword">new</span> String(<span class="hljs-string">&quot;1&quot;</span>);<br>String orderStatus2 = <span class="hljs-keyword">new</span> String(<span class="hljs-string">&quot;1&quot;</span>);<br>System.out.println(Integer.valueOf(orderStatus1) == Integer.valueOf(orderStatus2));<br></code></pre></div></td></tr></table></figure>
<ul>
<li>这样就会返回 true</li>
<li>只有这种特殊情况才会使判断结果相同，养成好喜欢，统一使用 <code>equals</code> 来判断相等。</li>
</ul>
<h2 id="3-「使用BigDecimal不丢失精度？」"><a href="#3-「使用BigDecimal不丢失精度？」" class="headerlink" title="3. 「使用BigDecimal不丢失精度？」"></a>3. 「使用BigDecimal不丢失精度？」</h2><p>涉及金融业务，不可避免接触到小数。</p>
<p>使用Double时出现的场景：</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">double</span> amount1 = <span class="hljs-number">0.02</span>;<br><span class="hljs-keyword">double</span> amount2 = <span class="hljs-number">0.03</span>;<br>System.out.println(amount2 - amount1); <span class="hljs-comment">// 0.009999999999999998</span><br></code></pre></div></td></tr></table></figure>
<p>结果小于预计结果。</p>
<ul>
<li>Double类型两个参数相减会转换为二进制，而Double有效位是16位，出现存储小数位不够。</li>
<li>使用 <code>BigDecimal</code> 就可以避免丢失精度吗？还是要看你怎么用。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">BigDecimal amount1 = <span class="hljs-keyword">new</span> BigDecimal(<span class="hljs-number">0.02</span>);<br>BigDecimal amount2 = <span class="hljs-keyword">new</span> BigDecimal(<span class="hljs-number">0.03</span>);<br>System.out.println(amount2.subtract(amount1));<br></code></pre></div></td></tr></table></figure>
<blockquote>
<p>0.0099999999999999984734433411404097569175064563751220703125</p>
</blockquote>
<p>可以看到仍然丢失精度。</p>
<p>看 <code>BigDecimal</code> 带 double 参数的构造方法上的注释</p>
<blockquote>
<p>Notes:</p>
<ol>
<li><p>The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.</p>
</li>
<li><p>The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal(“0.1”) creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.</p>
</li>
<li><p>When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.</p>
</li>
</ol>
</blockquote>
<ul>
<li><p><code>public BigDecimal(double val)</code> 这种构造方法生成的结果不可预测(unpredictable)</p>
</li>
<li><p>注释举例的 0.1 无法准确替换为double，即无法替换为任何有限长度的二进制分数</p>
</li>
<li><p>官方推荐入参选用 <code>String</code> 字符串，这样传入多少，生成多少。</p>
</li>
<li><p>如果非得用 <code>double</code> 入参，则先 <code>Double.toString(double)</code> 转成String再构造。</p>
</li>
<li><p>或者使用 <code>public static BigDecimal valueOf(double val)</code> 静态方法生成，也是阿里巴巴开发手册推荐的构造形式。</p>
</li>
</ul>
<h2 id="4-「字符串拼接不能用String？」"><a href="#4-「字符串拼接不能用String？」" class="headerlink" title="4.  「字符串拼接不能用String？」"></a>4.  「字符串拼接不能用String？」</h2><p><code>String</code>类型的字符串被称为不可变序列，在大量字符串拼接的场景中，如果对象定义为 String ，会产生很多无用的中间对象，浪费内存空间，效率低。</p>
<p>推荐使用更高效的可变字符序列：<code>StringBuilder</code> 和 <code>StringBuffer</code> </p>
<p><code>StringBuilder</code> 虽然线程不安全，但是多线程拼接字符串情况很少，所以就使用这个对象。<code>append</code> 方法追加字符串即可。</p>
<p><strong>「字符串拼接时使用String类型的对象，效率一定比StringBuilder类型的对象低？」</strong></p>
<p>否。</p>
<p>通过 <code>javap -c</code> 反编译可知，总JDK5开始，java对String拼接字符串进行优化，编译成字节码都会变成StringBuilder的append操作。</p>
<h2 id="5-「Map初始化注意事项」"><a href="#5-「Map初始化注意事项」" class="headerlink" title="5. 「Map初始化注意事项」"></a>5. 「Map初始化注意事项」</h2><ul>
<li>Map初始化同时导入数据有以下三种常见方法</li>
</ul>
<ol>
<li>static块初始化</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Map&lt;String, String&gt; myMap;<br><br>    <span class="hljs-keyword">static</span> &#123;<br>        myMap = <span class="hljs-keyword">new</span> HashMap&lt;String, String&gt;();<br>        myMap.put(<span class="hljs-string">&quot;a&quot;</span>, <span class="hljs-string">&quot;b&quot;</span>);<br>        myMap.put(<span class="hljs-string">&quot;c&quot;</span>, <span class="hljs-string">&quot;d&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li>Guava类库</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// 创建一个HashMap</span><br>Map&lt;String, Object&gt; hashMap  = Maps.newHashMap();<br><span class="hljs-comment">// 创建不可变Map</span><br>Map&lt;String, Integer&gt; left = ImmutableMap.of(<span class="hljs-string">&quot;a&quot;</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&quot;b&quot;</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&quot;c&quot;</span>, <span class="hljs-number">3</span>);<br><span class="hljs-comment">// 或者</span><br>Map&lt;String, String&gt; test = ImmutableMap.&lt;String, String&gt;builder()<br>.put(<span class="hljs-string">&quot;k1&quot;</span>, <span class="hljs-string">&quot;v1&quot;</span>)<br>.put(<span class="hljs-string">&quot;k2&quot;</span>, <span class="hljs-string">&quot;v2&quot;</span>)<br>.build();<br></code></pre></div></td></tr></table></figure>
<ol start="3">
<li>使用匿名内部类</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>&#123;<br>    Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>        put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>        put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>        put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>    &#125;&#125;;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>📌外层的括号是创建 <strong>匿名内部类</strong> 「Anonymous Inner Class」 ，<strong>这里会造成隐患</strong>。</li>
<li>内层是括号是创建 <strong>实例初始化块</strong> </li>
</ul>
<h3 id="①验证匿名内部类"><a href="#①验证匿名内部类" class="headerlink" title="①验证匿名内部类"></a>①验证匿名内部类</h3><ul>
<li>首先 <code>javac</code> 编译 .java 文件</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>&#123;<br>    Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>        put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>        put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>        put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>    &#125;&#125;;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/JavaCommons/image-20210515165844089.png" srcset="/img/loading.gif" lazyload style="zoom:150%;" />

<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/JavaCommons/image-20210515170722679.png" srcset="/img/loading.gif" lazyload></p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>$1 <span class="hljs-keyword">extends</span> <span class="hljs-title">HashMap</span> </span>&#123;<br>    Solution$<span class="hljs-number">1</span>(Solution var1) &#123;<br>        <span class="hljs-keyword">this</span>.<span class="hljs-keyword">this</span>$<span class="hljs-number">0</span> = var1;<br>        <span class="hljs-keyword">this</span>.put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>        <span class="hljs-keyword">this</span>.put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>        <span class="hljs-keyword">this</span>.put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>说明的确是创建了一个<strong>匿名内部类</strong></li>
</ul>
<h3 id="②非静态内部类持有外部类引用"><a href="#②非静态内部类持有外部类引用" class="headerlink" title="②非静态内部类持有外部类引用"></a>②非静态内部类持有外部类引用</h3><ul>
<li>Java 中<strong>非静态内部类</strong>会<strong>持有外部类的引用</strong>，从而导致 GC 无法回收这部分代码的引用，以至于造成<strong>内存溢出</strong>。</li>
</ul>
<ol>
<li>🍬为什么要<strong>持有外部类</strong>？</li>
</ol>
<p>非静态匿名内部类的主要作用有两个。</p>
<ul>
<li><p>当匿名内部类只在外部类（主类）中使用时，匿名内部类可以让外部不知道它的存在，从而减少了代码的维护工作。</p>
</li>
<li><p>当匿名内部类持有外部类时，它就可以直接<strong>使用外部类中的变量</strong>了，这样可以很方便的完成调用：</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String userName = <span class="hljs-string">&quot;hypocrite30&quot;</span>;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> NoSuchFieldException, IllegalAccessException </span>&#123;<br>        Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>            put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>            put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>            put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>            put(userName, userName);<br>        &#125;&#125;;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>内部类 <code>HashMap</code>  可以直接调用外部类 <code>Solution</code> 中的成员变量 <code>userName</code>.</li>
</ul>
<ol start="2">
<li>🍬它是怎么持有外部类的？</li>
</ol>
<ul>
<li><code>javap -c &#39;.\Solution$1.class&#39;</code> 反编译内部类</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>$1 <span class="hljs-keyword">extends</span> <span class="hljs-title">java</span>.<span class="hljs-title">util</span>.<span class="hljs-title">HashMap</span> </span>&#123;<br>  <span class="hljs-keyword">final</span> Solution <span class="hljs-keyword">this</span>$<span class="hljs-number">0</span>;<br><br>  Solution$<span class="hljs-number">1</span>(Solution);<br>    Code:<br>       <span class="hljs-number">0</span>: aload_0<br>       <span class="hljs-number">1</span>: aload_1<br>       2: putfield      #1                  // Field this$0:LSolution;<br>       <span class="hljs-number">5</span>: aload_0<br>       6: invokespecial #2                  // Method java/util/HashMap.&quot;&lt;init&gt;&quot;:()V<br>       <span class="hljs-number">9</span>: aload_0<br>      10: ldc           #3                  // String map1<br>      12: ldc           #4                  // String value1<br>      14: invokevirtual #5                  // Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br>      <span class="hljs-number">17</span>: pop<br>      <span class="hljs-number">18</span>: aload_0<br>      19: ldc           #6                  // String map2<br>      21: ldc           #7                  // String value2<br>      23: invokevirtual #5                  // Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br>      <span class="hljs-number">26</span>: pop<br>      <span class="hljs-number">27</span>: aload_0<br>      28: ldc           #8                  // String map3<br>      30: ldc           #9                  // String value3<br>      32: invokevirtual #5                  // Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br>      <span class="hljs-number">35</span>: pop<br>      <span class="hljs-number">36</span>: <span class="hljs-keyword">return</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><p>Code2:<code>putfield</code> ：一对 <code>Solution</code> 的引用被存入 <code>this$0</code> 中，此时该匿名内部类持有外部类的引用</p>
</li>
<li><p>另一种直观测试</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> NoSuchFieldException, IllegalAccessException </span>&#123;<br>        Map map = <span class="hljs-keyword">new</span> Solution().createMap();<br>        Field field = map.getClass().getDeclaredField(<span class="hljs-string">&quot;this$0&quot;</span>);<br>        field.setAccessible(<span class="hljs-keyword">true</span>);<br>        System.out.println(field.get(map).getClass());<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Map <span class="hljs-title">createMap</span><span class="hljs-params">()</span> </span>&#123;<br>        Map&lt;String, String&gt; map = <span class="hljs-keyword">new</span> HashMap&lt;&gt;() &#123;&#123;<br>            put(<span class="hljs-string">&quot;k1&quot;</span>, <span class="hljs-string">&quot;v1&quot;</span>);<br>            put(<span class="hljs-string">&quot;k2&quot;</span>, <span class="hljs-string">&quot;v2&quot;</span>);<br>        &#125;&#125;;<br>        <span class="hljs-keyword">return</span> map;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/JavaCommons/image-20210515200626985.png" srcset="/img/loading.gif" lazyload></p>
<blockquote>
<p> 执行结果：Solution</p>
</blockquote>
<p>结论：匿名内部类持有外部类的引用，所以使用 <code>$0</code> 可以正常获取外部类，输入相关信息。</p>
<h3 id="③匿名内部类隐患"><a href="#③匿名内部类隐患" class="headerlink" title="③匿名内部类隐患"></a>③匿名内部类隐患</h3><ul>
<li>正常代码：</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">createMap</span><span class="hljs-params">()</span> </span>&#123;<br>    Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>        put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>        put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>        put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>    &#125;&#125;;<br>    <span class="hljs-comment">// 业务逻辑</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>转换成这样就<strong>有可能</strong>造成<strong>内存泄漏</strong></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> Map <span class="hljs-title">createMap</span><span class="hljs-params">()</span> </span>&#123;<br>    Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>        put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>        put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>        put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>    &#125;&#125;;<br>    <span class="hljs-keyword">return</span> map;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<p>因为当此 <code>map</code> 被<strong>赋值为其他类属性</strong>时，可能会导致 GC 收集时不清理此对象，这时候才会导致<strong>内存泄漏</strong>。</p>
<p>非静态匿名内部类持有外部类引用，因此串行化这个集合时外部类也会被串行化，当外部类没有实现<code>serialize</code>接口时，就会报错。</p>
<ul>
<li>把 <code>map</code> 对象声明为 <code>static</code> 静态类型就不会泄漏内存</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Map <span class="hljs-title">createMap</span><span class="hljs-params">()</span> </span>&#123;<br>    Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>        put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>        put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>        put(<span class="hljs-string">&quot;map3&quot;</span>, <span class="hljs-string">&quot;value3&quot;</span>);<br>    &#125;&#125;;<br>    <span class="hljs-keyword">return</span> map;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>反编译查看</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>$1 <span class="hljs-keyword">extends</span> <span class="hljs-title">java</span>.<span class="hljs-title">util</span>.<span class="hljs-title">HashMap</span> </span>&#123;<br>  Solution$<span class="hljs-number">1</span>();<br>    Code:<br>       <span class="hljs-number">0</span>: aload_0<br>       1: invokespecial #1                  // Method java/util/HashMap.&quot;&lt;init&gt;&quot;:()V<br>       <span class="hljs-number">4</span>: aload_0<br>       5: ldc           #2                  // String map1<br>       7: ldc           #3                  // String value1<br>       9: invokevirtual #4                  // Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br>      <span class="hljs-number">12</span>: pop<br>      <span class="hljs-number">13</span>: aload_0<br>      14: ldc           #5                  // String map2<br>      16: ldc           #6                  // String value2<br>      18: invokevirtual #4                  // Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br>      <span class="hljs-number">21</span>: pop<br>      <span class="hljs-number">22</span>: aload_0<br>      23: ldc           #7                  // String map3<br>      25: ldc           #8                  // String value3<br>      27: invokevirtual #4                  // Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br>      <span class="hljs-number">30</span>: pop<br>      <span class="hljs-number">31</span>: <span class="hljs-keyword">return</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>没有 <code>putfield</code> 关键字，<strong>静态匿名类不会持有外部对象引用</strong> </li>
<li>因为匿名内部类是静态的之后，它所引用的对象或属性也必须是静态的了，因此就可以直接从 JVM 的 Method Area（方法区）获取到引用而无需持久外部对象了</li>
<li>尽管如此还是不建议使用双括号方式初始map</li>
</ul>
<h3 id="④替代方案"><a href="#④替代方案" class="headerlink" title="④替代方案"></a>④替代方案</h3><ol>
<li>Stream</li>
</ol>
<ul>
<li>Java8 的 Stream API</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">List list = <span class="hljs-keyword">new</span> ArrayList() &#123;&#123;<br>    add(<span class="hljs-string">&quot;Java&quot;</span>);<br>    add(<span class="hljs-string">&quot;Redis&quot;</span>);<br>&#125;&#125;;<br><span class="hljs-comment">// 替换为↓</span><br>List list = Stream.of(<span class="hljs-string">&quot;Java&quot;</span>, <span class="hljs-string">&quot;Redis&quot;</span>).collect(Collectors.toList());<br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li>Java9集合工厂</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Map map = <span class="hljs-keyword">new</span> HashMap() &#123;&#123;<br>    put(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;value1&quot;</span>);<br>    put(<span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;value2&quot;</span>);<br>&#125;&#125;;<br><span class="hljs-comment">// 替换为↓</span><br>Map map = Map.of(<span class="hljs-string">&quot;map1&quot;</span>, <span class="hljs-string">&quot;Java&quot;</span>, <span class="hljs-string">&quot;map2&quot;</span>, <span class="hljs-string">&quot;Redis&quot;</span>);<br></code></pre></div></td></tr></table></figure>
<blockquote>
<p>鸣谢：<a target="_blank" rel="noopener" href="https://www.cnblogs.com/vipstone/p/12937582.html">https://www.cnblogs.com/vipstone/p/12937582.html</a></p>
</blockquote>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/JavaSE/">JavaSE</a>
                    
                  </div>
                
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2021/06/02/JVM/JVM%E3%80%8CHotSpot%20VM%E3%80%8D/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">JVM「HotSpot VM」</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2021/04/22/Redis/Redis/">
                        <span class="hidden-mobile">Redis</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     © 2019-2021 
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" ></script>
<script  src="/js/debouncer.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  <script  src="https://cdn.jsdelivr.net/npm/tocbot@4.12.0/dist/tocbot.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4.3.0/anchor.min.js" ></script>



  <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2.0.11/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>



  <script  src="/js/local-search.js" ></script>
  <script>
    (function () {
      var path = "/local-search.xml";
      $('#local-search-input').on('click', function() {
        searchFunc(path, 'local-search-input', 'local-search-result');
      });
      $('#modalSearch').on('shown.bs.modal', function() {
        $('#local-search-input').focus();
      });
    })()
  </script>





  

  
    <!-- MathJax -->
    <script>
      MathJax = {
        tex: {
          inlineMath: [['$', '$'], ['\\(', '\\)']]
        },
        options: {
          renderActions: {
            findScript: [10, doc => {
              document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
                const display = !!node.type.match(/; *mode=display/);
                const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
                const text = document.createTextNode('');
                node.parentNode.replaceChild(text, node);
                math.start = { node: text, delim: '', n: 0 };
                math.end = { node: text, delim: '', n: 0 };
                doc.math.push(math);
              });
            }, '', false],
            insertedScript: [200, () => {
              document.querySelectorAll('mjx-container').forEach(node => {
                let target = node.parentNode;
                if (target.nodeName.toLowerCase() === 'li') {
                  target.parentNode.classList.add('has-jax');
                }
              });
            }, '', false]
          }
        }
      };
    </script>

    <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.1.2/es5/tex-svg.js" ></script>

  











<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
